package com.ipat.parser;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.htmlparser.Node;
import org.htmlparser.Parser;
import org.htmlparser.Tag;
import org.htmlparser.filters.CssSelectorNodeFilter;
import org.htmlparser.filters.OrFilter;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.tags.Span;
import org.htmlparser.tags.TableRow;
import org.htmlparser.tags.TableTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
import org.htmlparser.visitors.NodeVisitor;

import com.ipat.model.Patent;

public class RetrievePatentFamilyBean {

	private static final String REQUEST_URL = "http://v3.espacenet.com/inpadoc?DB=EPODOC&locale=en_EP&submitted=true&FT=D&CC=%COUNTRY_CODE%&NR=%NEXT_PART%&KC=A";
	
	public static void main(String[] args) {
		List<Patent> result = RetrievePatentFamilyBean.getPatentFamilyByPatentNum("US4476352 (A)");
		if(result != null) {
			for(Patent patent : result) {
				System.out.println(patent.toString());
			}
		}
	}
	
	public static List<Patent> getPatentFamilyByPatentNum(String patentNum) {
		long start = System.currentTimeMillis();
		List<Patent> result = new ArrayList<Patent>();
		// validate the format of patent number
		// step 1: remove all possible unnecessary symbols, such as ().? and white space
		patentNum = patentNum.replaceAll("[\\(|\\)|\\.|\\?|\\s]+", "");
		// step 2: check if the argument is matched with the format (Starting with exactly 2 characters, and following by 7 or 8 number and characters)
		Pattern pnPattern = Pattern.compile("^[a-zA-Z]{2}[\\w]{7,8}$");
		Matcher matcher = pnPattern.matcher(patentNum);
		if(matcher.matches()) {
			
			String countryCode = patentNum.substring(0, 2);
			String nextPart = patentNum.substring(2);
			
			String requestURL = REQUEST_URL.replaceAll("%COUNTRY_CODE%", countryCode).replaceAll("%NEXT_PART%", nextPart);
			
			try {
				long beforeRequest = System.currentTimeMillis();
				System.out.println((beforeRequest - start) + "(ms) elapsed to validate arguments");
				org.htmlparser.Parser parser = new Parser(requestURL);
				parser.setEncoding("UTF-8");
				
				NodeList trList = parser.parse(new OrFilter(
						new CssSelectorNodeFilter("tr.rowcol_family_hi"), 
						new CssSelectorNodeFilter("tr.rowcol_family")));
				long afterRequest = System.currentTimeMillis();
				System.out.println((afterRequest - beforeRequest) + "(ms) elapsed to get page from EUPTO");
				if(trList != null) {
					Node trNode = null;
					for(int i = 0; i < trList.size(); i++) {
						trNode = trList.elementAt(i);
						trNode.accept(new InfoVisitor(result));
					}
				}
				long afterProcess = System.currentTimeMillis();
				System.out.println((afterProcess - afterRequest) + "(ms) elapsed to parse and retrieve patent info");
				System.out.println((afterProcess - start) + "(ms) elapsed to perform this task\n");
			} catch (ParserException e) {
				e.printStackTrace();
			}
		}
		
		
		
		return result;
		
	}

}

class InfoVisitor extends NodeVisitor {
	
	List<Patent> container;
	private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
	
	public InfoVisitor(List<Patent> container) {
		this.container = container;
	}
	
	public void visitTag(Tag tag) {
		if(tag instanceof TableRow) {
			tag = (TableRow)tag;
			String styleClass = tag.getAttribute("class");
			if(styleClass != null && !styleClass.equals("")) {
				if(styleClass.equalsIgnoreCase("rowcol_family_hi")) {
					Patent patent = new Patent();
					NodeList titleAnchorList = new NodeList();
					//So far, the second anchor tag encloses the title
					tag.collectInto(titleAnchorList, new TagNameFilter("a"));
					if(titleAnchorList.size() > 0) {
						patent.setTitle(titleAnchorList.elementAt(1).toPlainTextString().trim());
					}
					container.add(patent);
				}
			}
		}
		else if(tag instanceof Span) {
			tag = (Span)tag;
			String styleClass = tag.getAttribute("class");
			
			if(styleClass != null && styleClass.equalsIgnoreCase("smallbold")) {
				Patent patent = container.get(container.size() - 1);
				String field = tag.toPlainTextString();
				
				if(field.indexOf("Inventor") >= 0) {
					Span inventorSpan = (Span)tag.getNextSibling().getNextSibling();
					if(inventorSpan != null) {
						String inventorStr = inventorSpan.toPlainTextString().trim();
						if(inventorStr != null && !inventorStr.equals("")) {
							patent.setInventors(getProcessedStringAsList(inventorStr));
						}
					}
				} 
				else if(field.indexOf("Applicant") >= 0) {
					Span applicantSpan = (Span)tag.getNextSibling().getNextSibling();
					if(applicantSpan != null) {
						String applicantStr = applicantSpan.toPlainTextString().trim();
						if(applicantStr != null && !applicantStr.equals("")) {
							patent.setApplicants(getProcessedStringAsList(applicantStr));
						}
					}
				}
				else if(field.indexOf("EC") >= 0) {
					Span ecSpan = (Span)tag.getNextSibling().getNextSibling();
					if(ecSpan != null) {
						String ecStr = ecSpan.toPlainTextString().trim();
						if(ecStr != null && !ecStr.equals("")) {
							patent.setEuropClassification(ecStr);
						}
					}
				}
				else if(field.indexOf("IPC") >= 0) {
					Span ipcSpan = (Span)tag.getNextSibling().getNextSibling();
					if(ipcSpan != null) {
						String ipcStr = ipcSpan.toPlainTextString().trim();
						if(ipcStr != null && !ipcStr.equals("")) {
							patent.setIntlClassification(getProcessedStringAsList(ipcStr));
						}
					}
				}
			}
		}
		else if(tag instanceof TableTag) {
			tag = (TableTag)tag;
			String id = tag.getAttribute("id");
			if(id != null && id.equalsIgnoreCase("pubinfo")) {
				NodeList pubInfoList = new NodeList();
				tag.collectInto(pubInfoList, new CssSelectorNodeFilter("td.small"));
				if(pubInfoList.size() > 0) {
					Patent patent = this.container.get(container.size() - 1); 
					Map<String, Date> pubInfoMap = new HashMap<String, Date>();
					for(int i = 0; i < pubInfoList.size(); i++) {
						String pubInfoStr = pubInfoList.elementAt(i).toPlainTextString().trim().replaceAll("\\s|&nbsp;", "");

						String[] pubInfo = pubInfoStr.split("&mdash;");
						if(pubInfo != null && pubInfo.length == 2) {
							try {
								pubInfoMap.put(pubInfo[0].trim(), sdf.parse(pubInfo[1]));
								if(i == 0) {
									patent.setPubNum(pubInfo[0].trim());
									patent.setPubDate(sdf.parse(pubInfo[1]));
								}
							} catch (ParseException e) {
								e.printStackTrace();
							}
						}
					}
					
					patent.setPriorityNum(pubInfoMap);
				}
			}
		}
		
	}
	
	
	private List<String> getProcessedStringAsList(String input) {
		if(input != null && !input.equals("")) {
			String[] tmp = input.trim().split(";");
			if(tmp != null && tmp.length > 0) {
				for(int i = 0; i < tmp.length; i++) {
					tmp[i] = tmp[i].trim();
				}
				
				return Arrays.asList(tmp);
			}
			else {
				return new ArrayList<String>();
			}
		}
		
		return new ArrayList<String>();
	}

}
